package com.glodon.paas.account.security.oauth1.service;

import com.glodon.paas.account.security.oauth1.provider.SimpleOAuthProvider;
import net.oauth.OAuth;
import net.oauth.OAuthAccessor;
import net.oauth.OAuthMessage;
import net.oauth.server.OAuthServlet;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.context.support.SpringBeanAutowiringSupport;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

import static com.google.common.base.Strings.isNullOrEmpty;

/**
 * @author Don Li
 */
public class AuthorizationServlet extends HttpServlet {

    @Autowired
    private SimpleOAuthProvider oauthProvider;

    public void init(ServletConfig config) throws ServletException {
        super.init(config);
        SpringBeanAutowiringSupport.processInjectionBasedOnServletContext(this, config.getServletContext());
    }

    @Override
    public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
        try {
            OAuthMessage requestMessage = OAuthServlet.getMessage(request, null);
            OAuthAccessor accessor = oauthProvider.getAccessor(requestMessage);

            if (Boolean.TRUE.equals(accessor.getProperty("authorized"))) {
                returnToConsumer(request, response, accessor);
            } else {
                sendToAuthorizePage(request, response, accessor);
            }
        } catch (Exception e) {
            oauthProvider.handleException(e, request, response, true);
        }
    }

    @Override
    public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
        try {
            OAuthMessage requestMessage = OAuthServlet.getMessage(request, null);
            OAuthAccessor accessor = oauthProvider.getAccessor(requestMessage);

            String userId = request.getParameter("uid");
            if (userId != null) {
                // set userId in accessor and mark it as authorized
                oauthProvider.markAsAuthorized(accessor, userId);
            } else {
                // invalidate (remove) request token
                oauthProvider.markAsDenied(accessor, userId);
            }

            boolean isHybrid = "on".equals(request.getParameter("hybrid"));
            if (isHybrid) {
                String url = (String) request.getSession(false).getAttribute("hybrid-protocol-callback");
                response.sendRedirect(url);
            } else {
                // return to consumer
                returnToConsumer(request, response, accessor);
            }
        } catch (Exception e) {
            oauthProvider.handleException(e, request, response, true);
        }
    }

    private void sendToAuthorizePage(HttpServletRequest request, HttpServletResponse response, OAuthAccessor accessor) throws IOException, ServletException {
        String consumer_description = (String) accessor.consumer.getProperty("description");
        request.setAttribute("consumer_desc", consumer_description);
        request.getRequestDispatcher("/authorize").forward(request, response);
    }

    private void returnToConsumer(HttpServletRequest request, HttpServletResponse response, OAuthAccessor accessor) throws IOException, ServletException {
        // send the user back to site's callBackUrl
        String callback = request.getParameter("oauth_callback");
        if (isNullOrEmpty(callback)) {
            callback = "none";
        }

        if ("none".equals(callback)
                && accessor.consumer.callbackURL != null
                && accessor.consumer.callbackURL.length() > 0) {
            // first check if we have something in our properties file
            callback = accessor.consumer.callbackURL;
        }

        Object prop = accessor.getProperty("authorized");
        boolean authorized = prop == null ? false : (Boolean) prop;
        if (authorized) {
            if ("none".equals(callback)) {
                // no call back it must be a client
                response.setContentType("text/plain");
                PrintWriter out = response.getWriter();
                out.println("You have successfully authorized '"
                        + accessor.consumer.getProperty("description")
                        + "'. Please close this browser window and click continue"
                        + " in the client.");
                out.close();
            } else {
                // if callback is not passed in, use the callback from config
                String token = accessor.requestToken;
                if (token != null) {
                    callback = OAuth.addParameters(callback, "oauth_token", token);
                }
                response.setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY);
                response.setHeader("Location", callback);
            }
        } else {
            if ("none".equals(callback)) {
                // no call back it must be a client
                response.setContentType("text/plain");
                PrintWriter out = response.getWriter();
                out.println("Authorization cancelled '"
                        + accessor.consumer.getProperty("description")
                        + "'. Please close this browser window and click continue"
                        + " in the client.");
                out.close();
            } else {
                // if callback is not passed in, use the callback from config
                response.setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY);
                response.setHeader("Location", callback);
            }
        }
    }
}
